.MACRO  initialize_stack
		LDI  R16,HIGH(RAMEND)
		OUT  SPH,R16 
		LDI  R16,LOW(RAMEND)
		OUT  SPL,R16
.ENDMACRO
.MACRO initialize_space
		LDI ZL, LOW(0x200)		// location of stack in memory at 0x200
		LDI ZH, HIGH(0x200)
.ENDMACRO

		initialize_stack		// initialize the stack at RAMEND
		initialize_space		// set Z pointer to address 0x200

		// load registers R16-R19 with values to generate numbers, numbers must be >30 but <250
		LDI R16, 23		// starting value
		LDI R17, 10		// loop counter to generate numbers

		// GenerateStackValues: 
		// start with initial value of 23 in R16 
		// subtract 9 from R16 and update and push R16 onto stack
		// add 14 to R16 and update and push R16 onto stack
		// decrement counter (R19) and loop GenerateStackValues 10 times
		// This will generate the following 20 numbers:
		// 14, 30, 21, 37, 28, 44, 35, 51, 42, 58
		// 49, 65, 56, 72, 63, 79, 70, 86, 77, 93
GenerateStackValues:
		SUBI R16, 9	// R16 = R16 - 9
		ST Z+, R16		// push value of R16 onto stack
		LDI R18, 16		// R17 = 16
		ADD R16, R18	// R16 = R16 + 16
		ST Z+, R16		// push value of R16 onto stack
		DEC R17			// decrement counter
		BRNE GenerateStackValues

		// Parse through the values on the stack
		// Check if divisible by 3, sum up all numbers divisible by 3, place in R20:R21
		// Check if divisible by 5, sum up all numbers divisible by 5, place in R23:R24
		LDI R17, 20						// loop counter to parse through stack 20 times
		initialize_space				// reset Z address pointer
CheckDivisibility:
		LD R16, Z+						// load value from the address that the Z pointer is pointing at and increment Z pointer
		MOV R18, R16					// copy value of R16 to R18
		CPI R18, 15						// compare R18 with 15
		BRGE ReduceValueByFifteen		// check if R18 is equal or greater than 15, if so reduce the value by 15
		RJMP DivByThree					// if value is less than 15, jump to DivBy3 to check if divisible by 3
ReduceValueByFifteen:					// reduce the value by 15 without changing the divisibility of 3 and 5
		SUBI R18, 15					// subtract 15 from R18
		CPI R18, 15						// compare R18 with 15
		BRGE ReduceValueByFifteen		// reduce by 15 until value is less than 15
DivByThree:
		MOV R19, R18					// copy value of R18 to R19
		CPI R19, 3						// compare R19 with 3
		BRGE ReduceByThree				// if R19 is greater than 3, reduce it by 3
		CPI R19, 0						// compare R19 with 0
		BREQ SumThree					// if divisible by 3, sum it up
ReduceByThree:
		SUBI R19, 3						// reduce R19 by 3
		CPI R19, 3						// compare R19 with 3
		BRGE ReduceByThree				// loop to reduce it until its less than 3
		CPI R19, 0						// check if remainder is 0, if so then divisible by three
		BRNE DivByFive					// branch to DivByFive if R19 is not divisible by three
SumThree:
		ADD R21, R16					// R21 = sum of all numbers divisible by 3
		BRCC DivByFive					// 8 bit carry
		inc R20							// inc R20
DivByFive:
		MOV R19, R18					// copy value of R18 to R19
		CPI R19, 5						// compare R19 with 5
		BRGE ReduceByFive				// if R19 is greater than 5, reduce it by 5
		CPI R19, 0						// compare R19 with 0
		BREQ SumFive					// if divisible by 5, sum it up
ReduceByFive:
		SUBI R19, 5						// reduce R19 by 5
		CPI R19, 5						// compare R19 with 5
		BRGE ReduceByFive				// loop to reduce it until its less than 3
		CPI R19, 0						// check if remainder is 9, if so then divisible by 5
		BRNE NextNumber					// Branch to next number
SumFive:
		ADD R24, R16					// R24 = sum of all numbers divisible by 5
		BRCC NextNumber					// 8 bit carry
		inc R23							// inc R20
NextNumber:
		dec R17							// decrement counter
		BRNE CheckDivisibility			// loop until counter is 0
DONE: